home *** CD-ROM | disk | FTP | other *** search
/ Ultra Pack / UltraComputing Partner Applications.iso / SunLabs / tclTK / src / tk4.0 / tkPreserve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-12-18  |  5.8 KB  |  231 lines

  1. /* 
  2.  * tkPreserve.c --
  3.  *
  4.  *    This file contains a collection of procedures that are used
  5.  *    to make sure that widget records and other data structures
  6.  *    aren't reallocated when there are nested procedures that
  7.  *    depend on their existence.
  8.  *
  9.  * Copyright (c) 1991-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  */
  15.  
  16. static char sccsid[] = "@(#) tkPreserve.c 1.10 94/12/17 16:31:51";
  17.  
  18. #include "tkPort.h"
  19. #include "tk.h"
  20.  
  21. /*
  22.  * The following data structure is used to keep track of all the
  23.  * Tk_Preserve calls that are still in effect.  It grows as needed
  24.  * to accommodate any number of calls in effect.
  25.  */
  26.  
  27. typedef struct {
  28.     ClientData clientData;    /* Address of preserved block. */
  29.     int refCount;        /* Number of Tk_Preserve calls in effect
  30.                  * for block. */
  31.     int mustFree;        /* Non-zero means Tk_EventuallyFree was
  32.                  * called while a Tk_Preserve call was in
  33.                  * effect, so the structure must be freed
  34.                  * when refCount becomes zero. */
  35.     Tk_FreeProc *freeProc;    /* Procedure to call to free. */
  36. } Reference;
  37.  
  38. static Reference *refArray;    /* First in array of references. */
  39. static int spaceAvl = 0;    /* Total number of structures available
  40.                  * at *firstRefPtr. */
  41. static int inUse = 0;        /* Count of structures currently in use
  42.                  * in refArray. */
  43. #define INITIAL_SIZE 2
  44.  
  45. /*
  46.  *----------------------------------------------------------------------
  47.  *
  48.  * Tk_Preserve --
  49.  *
  50.  *    This procedure is used by a procedure to declare its interest
  51.  *    in a particular block of memory, so that the block will not be
  52.  *    reallocated until a matching call to Tk_Release has been made.
  53.  *
  54.  * Results:
  55.  *    None.
  56.  *
  57.  * Side effects:
  58.  *    Information is retained so that the block of memory will
  59.  *    not be freed until at least the matching call to Tk_Release.
  60.  *
  61.  *----------------------------------------------------------------------
  62.  */
  63.  
  64. void
  65. Tk_Preserve(clientData)
  66.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  67. {
  68.     register Reference *refPtr;
  69.     int i;
  70.  
  71.     /*
  72.      * See if there is already a reference for this pointer.  If so,
  73.      * just increment its reference count.
  74.      */
  75.  
  76.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  77.     if (refPtr->clientData == clientData) {
  78.         refPtr->refCount++;
  79.         return;
  80.     }
  81.     }
  82.  
  83.     /*
  84.      * Make a reference array if it doesn't already exist, or make it
  85.      * bigger if it is full.
  86.      */
  87.  
  88.     if (inUse == spaceAvl) {
  89.     if (spaceAvl == 0) {
  90.         refArray = (Reference *) ckalloc((unsigned)
  91.             (INITIAL_SIZE*sizeof(Reference)));
  92.         spaceAvl = INITIAL_SIZE;
  93.     } else {
  94.         Reference *new;
  95.  
  96.         new = (Reference *) ckalloc((unsigned)
  97.             (2*spaceAvl*sizeof(Reference)));
  98.         memcpy((VOID *) new, (VOID *) refArray, spaceAvl*sizeof(Reference));
  99.         ckfree((char *) refArray);
  100.         refArray = new;
  101.         spaceAvl *= 2;
  102.     }
  103.     }
  104.  
  105.     /*
  106.      * Make a new entry for the new reference.
  107.      */
  108.  
  109.     refPtr = &refArray[inUse];
  110.     refPtr->clientData = clientData;
  111.     refPtr->refCount = 1;
  112.     refPtr->mustFree = 0;
  113.     inUse += 1;
  114. }
  115.  
  116. /*
  117.  *----------------------------------------------------------------------
  118.  *
  119.  * Tk_Release --
  120.  *
  121.  *    This procedure is called to cancel a previous call to
  122.  *    Tk_Preserve, thereby allowing a block of memory to be
  123.  *    freed (if no one else cares about it).
  124.  *
  125.  * Results:
  126.  *    None.
  127.  *
  128.  * Side effects:
  129.  *    If Tk_EventuallyFree has been called for clientData, and if
  130.  *    no other call to Tk_Preserve is still in effect, the block of
  131.  *    memory is freed.
  132.  *
  133.  *----------------------------------------------------------------------
  134.  */
  135.  
  136. void
  137. Tk_Release(clientData)
  138.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  139. {
  140.     register Reference *refPtr;
  141.     int i;
  142.  
  143.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  144.     if (refPtr->clientData != clientData) {
  145.         continue;
  146.     }
  147.     refPtr->refCount--;
  148.     if (refPtr->refCount == 0) {
  149.         if (refPtr->mustFree) {
  150.         if (refPtr->freeProc == (Tk_FreeProc *) free) {
  151.             ckfree((char *) refPtr->clientData);
  152.         } else {
  153.             (*refPtr->freeProc)(refPtr->clientData);
  154.         }
  155.         }
  156.  
  157.         /*
  158.          * Copy down the last reference in the array to fill the
  159.          * hole left by the unused reference.
  160.          */
  161.  
  162.         inUse--;
  163.         if (i < inUse) {
  164.         refArray[i] = refArray[inUse];
  165.         }
  166.     }
  167.     return;
  168.     }
  169.  
  170.     /*
  171.      * Reference not found.  This is a bug in the caller.
  172.      */
  173.  
  174.     panic("Tk_Release couldn't find reference for 0x%x", clientData);
  175. }
  176.  
  177. /*
  178.  *----------------------------------------------------------------------
  179.  *
  180.  * Tk_EventuallyFree --
  181.  *
  182.  *    Free up a block of memory, unless a call to Tk_Preserve is in
  183.  *    effect for that block.  In this case, defer the free until all
  184.  *    calls to Tk_Preserve have been undone by matching calls to
  185.  *    Tk_Release.
  186.  *
  187.  * Results:
  188.  *    None.
  189.  *
  190.  * Side effects:
  191.  *    Ptr may be released by calling free().
  192.  *
  193.  *----------------------------------------------------------------------
  194.  */
  195.  
  196. void
  197. Tk_EventuallyFree(clientData, freeProc)
  198.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  199.     Tk_FreeProc *freeProc;    /* Procedure to actually do free. */
  200. {
  201.     register Reference *refPtr;
  202.     int i;
  203.  
  204.     /*
  205.      * See if there is a reference for this pointer.  If so, set its
  206.      * "mustFree" flag (the flag had better not be set already!).
  207.      */
  208.  
  209.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  210.     if (refPtr->clientData != clientData) {
  211.         continue;
  212.     }
  213.     if (refPtr->mustFree) {
  214.         panic("Tk_EventuallyFree called twice for 0x%x\n", clientData);
  215.         }
  216.         refPtr->mustFree = 1;
  217.     refPtr->freeProc = freeProc;
  218.         return;
  219.     }
  220.  
  221.     /*
  222.      * No reference for this block.  Free it now.
  223.      */
  224.  
  225.     if (freeProc == (Tk_FreeProc *) free) {
  226.     ckfree((char *) clientData);
  227.     } else {
  228.     (*freeProc)(clientData);
  229.     }
  230. }
  231.